package priv.wangy.micro.common.utils.secret;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 3DES算法
 * 用于配置文件参数加解密
 *
 * @author 张嘉琪
 * @since 2022-08-02
 */
public class ThreeDesUtil {

    private static final String KEY_ALGORITHM = "DESede";

    private static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";

    /**
     * 配置文件中的密文密钥
     * 不可随意修改，故直接在代码中编辑
     */
    private static final byte[] YML_KEY = build3DesKey("wangy0607");

    /**
     * 构架3DES密钥
     * 密钥长度为24
     *
     * @param key 原始密钥
     * @return 构建后的密钥
     */
    public static byte[] build3DesKey(String key) {
        byte[] result = new byte[24];
        byte[] temp = key.getBytes(StandardCharsets.UTF_8);
        System.arraycopy(temp, 0, result, 0, Math.min(result.length, temp.length));
        return result;
    }

    /**
     * 加密
     *
     * @param data 待加密明文
     * @return 加密后密文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static String encrypt(String data) {
        byte[] in = data.getBytes(StandardCharsets.UTF_8);
        byte[] out = encrypt(YML_KEY, in);
        return Base64.getEncoder().encodeToString(out);
    }


    /**
     * 加密
     *
     * @param key  密钥
     * @param data 待加密明文
     * @return 加密后密文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static String encrypt(String key, String data) {
        byte[] desKey = build3DesKey(key);
        byte[] in = data.getBytes(StandardCharsets.UTF_8);
        byte[] out = encrypt(desKey, in);
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * 加密
     *
     * @param data 待加密明文
     * @return 加密后密文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static byte[] encrypt(byte[] data) {
        return encrypt(YML_KEY, data);
    }

    /**
     * 加密
     *
     * @param key  密钥
     * @param data 待加密明文
     * @return 加密后密文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static byte[] encrypt(byte[] key, byte[] data) {
        try {
            SecretKey desKey = new SecretKeySpec(key, KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, desKey);
            return cipher.doFinal(data);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
                 BadPaddingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 解密
     *
     * @param data 待解密数据
     * @return 解密后明文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static String decrypt(String data) {
        byte[] in = Base64.getDecoder().decode(data);
        byte[] out = decrypt(YML_KEY, in);
        assert out != null;
        return new String(out, StandardCharsets.UTF_8);
    }

    /**
     * 解密
     *
     * @param key  密钥
     * @param data 待解密数据
     * @return 解密后明文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    @Deprecated
    public static String decrypt(String key, String data) {
        byte[] desKey = build3DesKey(key);
        byte[] in = Base64.getDecoder().decode(data);
        byte[] out = decrypt(desKey, in);
        assert out != null;
        return new String(out, StandardCharsets.UTF_8);
    }

    /**
     * 解密
     *
     * @param data 待解密数据
     * @return 解密后明文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static byte[] decrypt(byte[] data) {
        return decrypt(YML_KEY, data);
    }

    /**
     * 解密
     *
     * @param key  密钥
     * @param data 待解密数据
     * @return 解密后明文
     * @author 张嘉琪
     * @since 2022-08-02
     */
    public static byte[] decrypt(byte[] key, byte[] data) {
        try {
            SecretKey desKey = new SecretKeySpec(key, KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, desKey);
            return cipher.doFinal(data);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
                 BadPaddingException e) {
            e.printStackTrace();
            return null;
        }
    }
}
